package com.flashflexpro.flexdirector.adapter.codec{
    import com.flashflexpro.flexdirector.adapter.descriptor.DescPropertyAuto;
    import com.flashflexpro.flexdirector.model.CodeStringValue;

    import mx.automation.Automation;
    import mx.automation.AutomationIDPart;
    import mx.automation.IAutomationObject;
    import mx.styles.IStyleClient;

    public class CodecDefault implements ICodec{


        /*
         protected function value2script( value:Object ):String{
         }*/

        public function encode( obj:Object, descProperty:DescPropertyAuto,
                                relativeParent:IAutomationObject ):CodeStringValue{
            var rt:CodeStringValue = new CodeStringValue();
            rt.desc = descProperty.getDto();
            rt.value = getMemberFromObject( obj, descProperty );
            rt.string = String( getValue( obj, rt.value, descProperty ) );
            rt.code = getCode( rt.value ) as String;
            return rt;
        }

        protected function getCode( value:Object ):String{

            if( value == null ){
                return "null";
            }
            else{
                var type:String = typeof( value );
                if( "string" == type ){
                    return "decodeURI(\"" + encodeURI( value.toString() ) + "\")";
                } else if( value is Date ){
                    var d:Date = value as Date;
                    return "new Date( " + d.getFullYear() + ", " + d.getMonth() + ", " + d.getDate() + ", " +
                            d.getHours() + ", " + d.getMinutes() + ", " + d.getSeconds() + ", " + d.getMilliseconds() +
                            ")";
                } else if( "boolean" == type || "number" == type ){
                    return String( value );
                } else if( value is Array ){
                    var arr:Array = value as Array;
                    var arrVal:Array = [];
                    for( var i:int = 0; i < arr.length; i ++ ){
                        arrVal[ i ] = getCode( arr[ i ] );
                    }
                    return "[" + arrVal.join( "," ) + "]";
                }
                else{
                    throw new Error( "dont' know what type of " + value );
                }
            }
        }

        public function decode( obj:Object, value:Object, descProperty:DescPropertyAuto,
                                relativeParent:IAutomationObject, inString:Boolean = false ):void{
            if( inString ){
                obj[ descProperty.name ] = getValue( obj, value, descProperty, true );
            }
            else{
                obj[ descProperty.name ] = value;
            }
        }

        /*
         */
        public static function getMemberFromObject( obj:Object, pd:DescPropertyAuto ):Object{
            if( obj == null ){
                return null;
            }

            var idPart:Object;
            if( (obj is IAutomationObject) ){
                idPart = Automation.automationManager.createIDPart( (obj as IAutomationObject) );
            }

            if( idPart != null && pd.name in idPart ){
                return (idPart[pd.name]);
            }

            if( (pd.name in obj) ){
                return (obj[pd.name]);
            }

            if( (obj is IStyleClient) ){
                pd.isStyle = true;
                return (IStyleClient( obj ).getStyle( pd.name ));
            }
            
            return null;
        }

        protected function getValue( obj:Object, val:Object, pd:DescPropertyAuto, useASType:Boolean = false ):Object{
            if( val == null ){
                return "";
            }

            var type:String = useASType && pd.asType ? pd.asType : "string";

            switch( type ){
                case "Boolean":
                case "boolean":
                    if( val is Boolean ){
                        return val;
                    }
                    val = val ? val.toString().toLowerCase() : "false";
                    return val == "true";
                case "String":
                case "string":
                    if( val is String ){
                        return val;
                    }
                    return val.toString();
                case "int":
                case "uint":
                case "integer":
                    if( val is int || val is uint ){
                        return val;
                    }
                    if( val is Date ){
                        return val.time;
                    }
                    if( val is Number ){
                        throw new Error( "Precision loss is occuring for " + pd.name );
                    }
                    return parseInt( val.toString() );
                case "Number":
                case "decimal":
                    if( val is Number ){
                        return val;
                    }
                    if( val is Date ){
                        return val.time;
                    }
                    return parseFloat( val.toString() );
                case "Date":
                case "date":
                    if( val is Date ){
                        return val;
                    }
                    var num:Number = Date.parse( val.toString() );
                    return new Date( num );
                default:
                    return val;
            }
        }
    }
}